/**
 *	Yggdrasil World Framework Toolkit
 *	(A component of the NeuroCoSA toolkit)
 *	Copyright (C) 2001-5 Stuart Meikle.
 *
 *	This is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 * @author	Stuart Meikle
 * @version	2006-halloween
 * @license	LGPL
 */

package org.stumeikle.Yggdrasil;

//
// sensewatcher class.
// CLIENT Side class, just to make user coding simpler
//
// Copyright (C) Stuart Meikle Thu Apr  5 07:07:05 2001
//
// this class waits on sense objcets coming in from the server
// and updates the client side copy appropriately. would not be
// required if the available() method worked properly!!!
//

//$Author: stumeikle $
//$Date: 2003/10/10 16:51:31 $
//$Revision: 1.3 $
//
//$Log: SenseWatcher.java,v $
//Revision 1.3  2003/10/10 16:51:31  stumeikle
//all things basically operational
//
//Revision 1.2  2001/05/27 11:01:57  stuart
//able to send senses to a client now
//
//Revision 1.1  2001/04/20 15:00:14  stuart
//Initial revision
//
//Revision 1.1  2001/04/05 05:32:01  stuart
//Initial revision
//

//
// FUTURE WORK = make actions and senses generic data blocks and use the
// same class here for both sense and action watcher
//

import java.net.*;
import java.lang.*;
import java.io.*;
import org.stumeikle.NeuroCoSA.DataBlock;

public class SenseWatcher extends Thread
{
    private DataBlock		outgoing_senses;
    private Socket		input_socket;
    private ObjectInputStream 	oipStream;
    protected 	Object		iLocker; //who has locked the senses ?

    public SenseWatcher( Socket inputsoc )
    {
	input_socket   = inputsoc;
	outgoing_senses= null;
	iLocker =null;
    }

    public void	run()
    {
	//get the incoming actions
	//wait on senses from the server
	DataBlock s; //senses

	try
	{
	    oipStream = new ObjectInputStream( input_socket.getInputStream() );
	}
	catch(Exception e)
	{
	    System.out.println("SENSEWATCHER:! problem creating input stream");
	}

	do
	{
	    s = null;
	    try
	    {
        	s = (DataBlock) oipStream.readObject();
		//System.out.println("SenseWatcher: received a sense, v=" + s.getVersion());
		//don't care about the details for now!
	    }
	    catch(Exception e)
	    {
		System.out.println("SENSEWATCHER: exception");
		s= null;
	    }

	    if (s!=null)
	    {
	        //copy over to the server. version in incoming object should be
	        //greater than previous action anyway.

		// need an object copy thing here ... (somehow)
		//senses.copy(s);// KRAP

		//20031103 change to non-in-situ copying
		//any senses here which are not claimed will be garbage collected
//		lockSenses(this);
		outgoing_senses =  (DataBlock) s.clone();	
//		unlockSenses(this);
		yield();	//pause this thread a moment to let nervous system get the data
	    }    
	} while(true);

	//oipStream.close();
    }

    DataBlock	getSenses(Object locker)
    {
// 	if (iLocker!=null)
// 	{
// 	    try{ wait(); } 
// 	    catch(Exception e){}
// 	}
        return outgoing_senses;
    }

    public synchronized void	lockSenses(Object l)
    {
	if (iLocker != null)
	{
	    //someone else has locked the data
	    try{ wait(); } 
	    catch(Exception e) {}
	}

	//now we lock the data
	iLocker = l;
    }

    public synchronized void	unlockSenses(Object l)
    {
	if (iLocker==l)	//if we locked the data
	{
	    iLocker=null;
	    notifyAll();	//free any lockers who're waiting
	}
    }

    public DataBlock	waitForNewSenses(Object locker)
    {
	//allow clients to block until senses returned
	DataBlock 	s=null;

	do
	{
       	    lockSenses(locker); //will block
	    if (outgoing_senses!=null)     s = (DataBlock) outgoing_senses;
	    unlockSenses(locker);
        } while (s==null);
	return s;
    }
}

